﻿using Bouyei.NetFactory.Protocols.Exceptions;
using Bouyei.NetFactory.Protocols.Quic.Packets;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading.Tasks;

namespace Bouyei.NetFactory.Protocols.Quic.InternalInfrastructure
{
    internal class PacketWireTransfer
    {
        private UdpClient _client;
        private INetClientProvider client;
        private INetServerProvider server;
        private SocketToken sToken;

        private IPEndPoint _peerEndpoint;

        private Unpacker _unpacker;

        public PacketWireTransfer(UdpClient client, IPEndPoint peerEndpoint)
        {
            _client = client;
            _peerEndpoint = peerEndpoint;

            _unpacker = new Unpacker();
        }

        public PacketWireTransfer(INetClientProvider client, IPEndPoint peerEndpoint)
        {
            this.client = client;
            _peerEndpoint = peerEndpoint;

            _unpacker = new Unpacker();
        }

        public PacketWireTransfer(INetServerProvider server, SocketToken sToken)
        {
            this.server = server;
            this.sToken = sToken;
            if (sToken != null)
                _peerEndpoint = sToken.TokenIpEndPoint;

            _unpacker = new Unpacker();
        }


        public Packets.Packet ReadPacket()
        {
            // Await response for sucessfull connection creation by the server
            byte[] peerData = _client.Receive(ref _peerEndpoint);
            if (peerData == null)
                throw new QuicConnectivityException("Server did not respond properly.");

            Packets.Packet packet = _unpacker.Unpack(peerData, peerData.Length);

            return packet;
        }

        public Packets.Packet Read(byte[] buffer, int size, int offset = 0)
        {
            // Await response for sucessfull connection creation by the server
            //byte[] peerData = _client.Receive(ref _peerEndpoint);
            //if (peerData == null)
            //    throw new QuicConnectivityException("Server did not respond properly.");

            Packets.Packet packet = _unpacker.Unpack(buffer, size, offset);

            return packet;
        }

        public bool SendPacket(Packets.Packet packet)
        {
            byte[] data = packet.Encode();

            int sent = _client.Send(data, data.Length, _peerEndpoint);

            return sent > 0;
        }

        public bool Send(Packets.Packet packet)
        {
            byte[] data = packet.Encode();
            if (client != null)
                return client.Send(new SegmentOffset(data, 0, data.Length));
            else if (server != null)
               return server.Send(new SegmentToken()
                {
                    sToken = sToken,
                    Data = new SegmentOffset()
                    {
                        buffer = data,
                        offset = 0,
                        size = data.Length
                    }
                });

            return false;
        }

        public IPEndPoint LastTransferEndpoint()
        {
            return _peerEndpoint;
        }
    }
}
